package com.example.ass7.geometryprimitives;

import java.util.ArrayList;
import java.util.List;

import com.example.ass7.Equation;

/**
 * @author Meirav Ben Izhak.
 */
public class Line {
    // members
    private final Point start;
    private final Point end;
    private double length;

    /**
     * @param start
     *            point that represents the line's begining.
     * @param end
     *            point that represents the line's ending.
     */
    public Line(Point start, Point end) {
        this.start = start;
        this.end = end;
        // this.middle = this.middle();
    }

    /**
     * @param x1
     *            start point x
     * @param y1
     *            start point y
     * @param x2
     *            end point x
     * @param y2
     *            end point y
     */
    public Line(double x1, double y1, double x2, double y2) {
        this.start = new Point(x1, y1);
        this.end = new Point(x2, y2);
    }

    /**
     * @return length calculated.
     */
    public double length() {
        this.length = this.start.distance(this.end);
        return this.length;
    }

    /**
     * @return middle.
     */
    public Point middle() {
        double x = this.start.getX() + this.end.getX();
        double y = this.start.getY() + this.end.getY();

        double xHalf = x / 2;
        double yHalf = y / 2;

        Point middle = new Point(xHalf, yHalf);

        return middle;
    }

    /**
     * @return start.
     */
    public Point start() {
        return this.start;
    }

    /**
     * @return end.
     */
    public Point end() {
        return this.end;
    }

    /**
     * @param other
     *            line to check intersection with.
     * @return true or false.
     */
    public boolean isIntersecting(Line other) {

        Equation eq1 = new Equation(this);
        Equation eq2 = new Equation(other);

        Point intersect = eq1.getIntersection(eq2);

        boolean intersectionInThis = this.isIntersectionInLine(intersect);
        boolean intersectionInOther = other.isIntersectionInLine(intersect);

        return intersectionInThis && intersectionInOther;
    }

    // Returns the intersection point if the lines intersect,
    // and null otherwise.
    /**
     * @param other
     *            line to find intersection with.
     * @return the intersection point or null.
     */
    public Point intersectionWith(Line other) {

        Point intersection = null;
        // the original condition :if (this.isIntersecting(other) == true) {
        // my attempt to simplify:
        if (this.isIntersecting(other)) {
            Equation eq1 = new Equation(this);
            Equation eq2 = new Equation(other);

            intersection = eq1.getIntersection(eq2);
        }

        return intersection;
    }

    /**
     * @param intersect
     *            intersection point.
     * @return true if it's in both lines, false if not.
     */
    public boolean isIntersectionInLine(Point intersect) {
        boolean intersectionIsOnLine = false;

        double k = 0.0000000001;

        // checking if intersection is on line1
        double minX = Point.min(this.end().getX(), this.start().getX()) - k;
        double maxX = Point.max(this.end().getX(), this.start().getX()) + k;
        double minY = Point.min(this.end().getY(), this.start().getY()) - k;
        double maxY = Point.max(this.end().getY(), this.start().getY()) + k;

        boolean yBoarders = intersect.getY() <= maxY
                && intersect.getY() >= minY;
        boolean xBoarders = intersect.getX() <= maxX
                && intersect.getX() >= minX;

        if (yBoarders && xBoarders) {
            intersectionIsOnLine = true;
        }
        return intersectionIsOnLine;
    }

    /**
     * @param rect
     *            rectangle with which the intersections are.
     * @return toReturn the point that is closest to the start.
     */
    public Point closestIntersectionToStartOfLine(Rectangle rect) {
        Line l1 = this;
        List<Point> inters = new ArrayList<Point>();
        inters = rect.intersectionPoints(l1);
        Point toReturn = this.closestPointToStart(inters);
        return toReturn;
    }

    /**
     * @param pointList
     *            pointList
     * @return Point
     */
    public Point closestPointToStart(List<Point> pointList) {
        Point colsestToStart;
        if (pointList.size() == 0) {
            colsestToStart = null;
        } else if (pointList.size() == 1) {
            colsestToStart = pointList.get(0);
        } else {
            double distanceFromStart1 = pointList.get(0).distance(this.start);
            double distanceFromStart2 = pointList.get(1).distance(this.start);
            if (distanceFromStart1 < distanceFromStart2) {
                colsestToStart = pointList.get(0);
            } else {
                colsestToStart = pointList.get(1);
            }
        }

        return colsestToStart;
    }

}
